package com.fliad.ai.components;

import cn.hutool.core.map.MapUtil;
import com.fliad.ai.dto.taskmodel.NodeReport;
import com.fliad.ai.dto.taskmodel.TaskReportOutput;
import org.noear.snack.ONode;
import org.noear.solon.ai.chat.ChatConfig;
import org.noear.solon.ai.chat.ChatModel;
import org.noear.solon.ai.chat.message.ChatMessage;
import org.noear.solon.ai.flow.components.AbsAiComponent;
import org.noear.solon.annotation.Component;
import org.noear.solon.expression.snel.SnEL;
import org.noear.solon.flow.FlowContext;
import org.noear.solon.flow.Node;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author wyl
 * @date 2025年07月07日 21:53
 */
@Component("llm")
public class LlmCom extends AbsAiComponent {

    @Override
    protected void doRun(FlowContext context, Node node) throws Throwable {
        Map<String, Object> variableContext = context.get("variableContext");
        // 解析节点的参数
        ONode inputsValues = node.getMeta("inputsValues");

        ChatConfig chatConfig = new ChatConfig();
        chatConfig.setApiUrl(getValueByKey(inputsValues, "apiHost", variableContext));
        chatConfig.setApiKey(getValueByKey(inputsValues, "apiKey", variableContext));
        chatConfig.setModel(getValueByKey(inputsValues, "modelName", variableContext));
        ChatModel.Builder chatModelBuilder = ChatModel.of(chatConfig);
        ChatModel chatModel = chatModelBuilder.build();

        ChatMessage sysMsg = ChatMessage.ofSystem(getValueByKey(inputsValues, "systemPrompt", variableContext));
        ChatMessage userMsg = ChatMessage.ofUser(getValueByKey(inputsValues, "prompt", variableContext));
        String res = chatModel.prompt(sysMsg, userMsg).call().getMessage().getContent();

        // 设置输出
        Map<String, Object> nodeMap = new HashMap<>();
        nodeMap.put("result", res);
        variableContext.put(node.getId(), nodeMap);

        // 设置报告
        TaskReportOutput report = context.get("report");
        NodeReport nodeReport = report.getReports().get(node.getId());
        Map<String, Object> inputMap = new HashMap<>();
        inputMap.put("input", getValueByKey(inputsValues, "prompt", variableContext));
        nodeReport.getLastSnapshot().setInputs(inputMap);
        nodeReport.getLastSnapshot().setOutputs(MapUtil.of("result", res));
    }

    /**
     * 正则表达式模式：匹配 {{variable}} 格式
     * - 支持变量名包含：字母、数字、下划线、点号、短横线、中文等常见字符
     * - 自动处理两端空白字符
     */
    private static final Pattern FRONTEND_PATTERN = Pattern.compile("\\{\\{\\s*([^{}]+?)\\s*\\}\\}");

    /**
     * 将前端模板语法 {{variable}} 转换为 #{variable}
     *
     * @param template 包含 {{variable}} 的模板字符串
     * @return 转换后的模板字符串
     */
    public static String convertTemplateSyntax(String template) {
        if (template == null || template.isEmpty()) {
            return template;
        }

        StringBuffer result = new StringBuffer();
        Matcher matcher = FRONTEND_PATTERN.matcher(template);

        while (matcher.find()) {
            // 提取并清理变量名（移除两端空格）
            String variable = matcher.group(1).trim();
            // 构造替换内容
            String replacement = "#{" + variable + "}";
            // 处理正则特殊字符转义
            matcher.appendReplacement(result, Matcher.quoteReplacement(replacement));
        }
        matcher.appendTail(result);

        return result.toString();
    }

    /**
     * 根据key获取解析后的值
     *
     * @param inputsValues    输入值节点
     * @param key             要获取的键名
     * @param variableContext 变量上下文
     * @return 解析后的字符串值
     */
    private String getValueByKey(ONode inputsValues, String key, Map<String, Object> variableContext) {
        ONode keyNode = inputsValues.get(key);
        String type = keyNode.get("type").getString();
        String content = keyNode.get("content").getString();

        if ("constant".equals(type)) {
            return content;
        } else if ("template".equals(type)) {
            return SnEL.evalTmpl(convertTemplateSyntax(content), variableContext).toString();
        }
        return ""; // 默认返回空字符串
    }
}
